/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.andremion.louvre.loader;

import com.andremion.louvre.data.Album;

import ohos.aafwk.ability.DataAbilityHelper;
import ohos.aafwk.ability.DataAbilityRemoteException;
import ohos.aafwk.ability.DataUriUtils;
import ohos.app.Context;
import ohos.data.dataability.DataAbilityPredicates;
import ohos.data.resultset.CombinedResultSet;
import ohos.data.resultset.ResultSet;
import ohos.data.resultset.TableResultSet;
import ohos.media.photokit.metadata.AVStorage;
import ohos.utils.net.Uri;

import java.util.*;

/**
 * AlbumLoader
 */
public class AlbumLoader {
    /**
     * COLUMN_URI
     */
    public static final String COLUMN_URI = "uri";
    /**
     * COLUMN_COUNT
     */

    public static final String COLUMN_COUNT = "count";
    private static final String COLUMN_BUCKET_ID = "_id";
    private static final String COLUMN_BUCKET_DISPLAY_NAME = "_display_name";

    private static final String[] COLUMNS = {
            AVStorage.AVBaseColumns.ID,
            COLUMN_BUCKET_ID,
            COLUMN_BUCKET_DISPLAY_NAME,
            AVStorage.AVBaseColumns.MIME_TYPE,
            COLUMN_URI,
            COLUMN_COUNT};

    private static final String[] PROJECTION_29 = {
            COLUMN_BUCKET_ID,
            AVStorage.AVBaseColumns.DATA,
            AVStorage.AVBaseColumns.DISPLAY_NAME,
            AVStorage.AVBaseColumns.MIME_TYPE};
    /**
     * mImageTypeQuery
     */
    private static String mImageTypeQuery = AVStorage.AVBaseColumns.MIME_TYPE + "=?"
            + " OR " + AVStorage.AVBaseColumns.MIME_TYPE + "=?"
            + " OR " + AVStorage.AVBaseColumns.MIME_TYPE + "=?"
            + " AND " + AVStorage.AVBaseColumns.SIZE + ">0";
    /**
     * mImageType
     */
    private static String[] mImageType = new String[]{"image/jpeg", "image/png", "image/bmp"};

    /**
     * setSelectionArgsForSingleMediaType
     *
     * @param mImageType mImageType Array
     */
    public void setSelectionArgsForSingleMediaType(String[] mImageType) {
        if (mImageType != null && mImageType.length > 0) {
            this.mImageType = mImageType;
        }
        if (mImageType.length == 1) {
            mImageTypeQuery = AVStorage.AVBaseColumns.MIME_TYPE + "=?"
                    + " AND " + AVStorage.AVBaseColumns.SIZE + ">0";
        } else if (mImageType.length == 2) {
            mImageTypeQuery = AVStorage.AVBaseColumns.MIME_TYPE + "=?"
                    + " OR " + AVStorage.AVBaseColumns.MIME_TYPE + "=?"
                    + " AND " + AVStorage.AVBaseColumns.SIZE + ">0";
        } else {
            mImageTypeQuery = AVStorage.AVBaseColumns.MIME_TYPE + "=?"
                    + " OR " + AVStorage.AVBaseColumns.MIME_TYPE + "=?"
                    + " OR " + AVStorage.AVBaseColumns.MIME_TYPE + "=?"
                    + " AND " + AVStorage.AVBaseColumns.SIZE + ">0";
        }
    }

    // =============================================

    private static final String BUCKET_ORDER_BY = "datetaken DESC";
    private Context mContext;
    private LoaderTask loaderTask;
    private LoaderCallback<ResultSet> loaderCallback;
    private String[] selectionArgs;

    /**
     * setContext
     *
     * @param mContext Context
     */
    public void setContext(Context mContext) {
        this.mContext = mContext;
    }

    /**
     * getContext
     *
     * @return Contex
     */
    public Context getContext() {
        return mContext;
    }

    public AlbumLoader(Context mContext) {
        this.mContext = mContext;
    }

    /**
     * setLoaderCallback
     *
     * @param loaderCallback loaderCallback
     */
    public void setLoaderCallback(LoaderCallback<ResultSet> loaderCallback) {
        this.loaderCallback = loaderCallback;
    }

    /**
     * load
     */
    public void load() {
        String selection;
        int isVideo = -1;
        selection = mImageTypeQuery;
        selectionArgs = mImageType;
        isVideo = 0;
        loaderTask = new LoaderTask(selection, selectionArgs, isVideo);
        loaderTask.execute();
    }

    /**
     * cancel
     *
     * @param interruptlf Boolean
     */
    public void cancel(boolean interruptlf) {
        if (interruptlf) {
            loaderCallback = null;
        }
        if (loaderTask != null) {
            loaderTask.cancel(interruptlf);
        }
    }

    class LoaderTask extends AsyncTaskLoader<String, ResultSet> {
        private String selection;
        private String[] selectionArgs;
        private int isVideo;

        LoaderTask(String selection, String[] selectionArgs, int isVideo) {
            this.selection = selection;
            this.selectionArgs = selectionArgs;
            this.isVideo = isVideo;
        }


        @Override
        protected ResultSet doInBackground(String[] strings) {
            ResultSet mTempResultSet = null;
            try {
                DataAbilityHelper helper = DataAbilityHelper.creator(getContext());
                ResultSet resultSet;
                if (selection != null) {
                    DataAbilityPredicates predicates = new DataAbilityPredicates(selection);
                    predicates.setWhereArgs(Arrays.asList(selectionArgs));
                    if (isVideo == 0) {
                        resultSet = helper.query(AVStorage.Images.Media
                                .EXTERNAL_DATA_ABILITY_URI, PROJECTION_29, predicates);
                    } else if (isVideo == 1) {
                        resultSet = helper.query(AVStorage.Video.Media
                                .EXTERNAL_DATA_ABILITY_URI, PROJECTION_29, predicates);
                    } else {
                        resultSet = helper.query(AVStorage.Files.fetchResource("external"), PROJECTION_29, predicates);
                    }
                } else {
                    resultSet = helper.query(AVStorage.Files.fetchResource("external"), PROJECTION_29, null);
                }

                if (resultSet == null) {
                    helper.release();
                    return mTempResultSet;
                }
                TableResultSet allAlbum = new TableResultSet(COLUMNS);
                int totalCount = 0;
                Uri allAlbumCoverUri = null;

                // Pseudo GROUP BY
                Map<String, Long> countMap = new HashMap<>();
                if (resultSet != null) {
                    while (resultSet.goToNextRow()) {
                        String data = resultSet.getString(resultSet.getColumnIndexForName(AVStorage
                                .AVBaseColumns.DATA));
                        String mimeType = resultSet.getString(resultSet
                                .getColumnIndexForName(AVStorage.AVBaseColumns.MIME_TYPE));
                        if (MimeType.isVideo(mimeType) || MimeType.isImage(mimeType)) {
                            int last = data.lastIndexOf("/");
                            String lastString = data.substring(0, last);
                            Long count = countMap.get(lastString);
                            if (count == null) {
                                count = 1L;
                            } else {
                                count++;
                            }
                            countMap.put(lastString, count);
                        }
                    }
                }
                TableResultSet otherAlbums = new TableResultSet(COLUMNS);
                if (resultSet != null) {
                    if (resultSet.goToFirstRow()) {
                        Set<String> done = new HashSet<>();
                        do {
                            long bucketId = resultSet.getLong(resultSet.getColumnIndexForName(COLUMN_BUCKET_ID));
                            String data = resultSet.getString(
                                    resultSet.getColumnIndexForName(AVStorage.AVBaseColumns.DATA));
                            String mimeType = resultSet.getString(resultSet
                                    .getColumnIndexForName(AVStorage.AVBaseColumns.MIME_TYPE));
                            if (MimeType.isVideo(mimeType) || MimeType.isImage(mimeType)) {
                                if (allAlbumCoverUri == null) {
                                    allAlbumCoverUri = getUri(resultSet);
                                }

                                int last = data.lastIndexOf("/");
                                String lastString = data.substring(0, last);

                                int last2 = lastString.lastIndexOf("/");
                                String lastString2 = lastString.substring(last2 + 1);

                                if (done.contains(lastString)) {
                                    continue;
                                }
                                long fileId = resultSet.getLong(
                                        resultSet.getColumnIndexForName(AVStorage.AVBaseColumns.ID));
                                Uri uri = getUri(resultSet);
                                long count = countMap.get(lastString);

                                otherAlbums.addRow(new String[]{
                                        Long.toString(fileId),
                                        Long.toString(bucketId),
                                        lastString2,
                                        mimeType,
                                        uri.toString(),
                                        String.valueOf(count)});
                                done.add(lastString);

                                totalCount += count;
                            }

                        } while (resultSet.goToNextRow());
                    }
                }

                allAlbum.addRow(new String[]{
                        Album.ALBUM_ID_ALL,
                        Album.ALBUM_ID_ALL, Album.ALBUM_NAME_ALL, null,
                        allAlbumCoverUri == null ? null : allAlbumCoverUri.toString(),
                        String.valueOf(totalCount)});
                helper.release();
                return new CombinedResultSet(new ResultSet[]{allAlbum, otherAlbums});
            } catch (DataAbilityRemoteException dataAbilityRemoteException) {
                return mTempResultSet;
            }
        }

        private Uri getUri(ResultSet cursor) {
            long id = cursor.getLong(cursor.getColumnIndexForName(AVStorage.AVBaseColumns.ID));
            Uri contentUri;
            contentUri = AVStorage.Images.Media.EXTERNAL_DATA_ABILITY_URI;
            return DataUriUtils.attachId(contentUri, id);
        }

        @Override
        protected void postResult(ResultSet albums) {
            super.postResult(albums);
            if (loaderCallback != null && albums != null) {
                loaderCallback.setCallback(albums);
            }
        }
    }
}
